﻿using System;
using System.Configuration;

using Ninject;
using Ninject.Modules;
using Ninject.Parameters;

using NUnit.Framework;

using mvcForum.Core;
using mvcForum.Core.Abstractions.Interfaces;
using mvcForum.Core.Abstractions.Interfaces.DependencyManagement;
using System.Collections.Generic;
using NHibernate;

namespace mvcForum.Tests.DataProvider {

	[TestFixture]
	public class InitialSetupTest {
		private IKernel kernel;

		public class TestUserProvider : IUserProvider {

			public bool Authenticated {
				get { return false; }
			}

			public int CurrentUserId {
				get { return -1; }
			}
		}

		public class TestCache : IPerRequestCache {

			public T Pull<T>(int id) where T : ICacheable {
				return default(T);
			}

			public void Push<T>(T element) where T : ICacheable {
			}

			public object Pull(string key) {
				return null;
			}

			public void Push(string key, object value) {
			}
		}

		public class TestModule : NinjectModule {
			public override void Load() {
				Bind<IUserProvider>().To<TestUserProvider>().InRequestScope();
				Bind<IPerRequestCache>().To<TestCache>().InRequestScope();
			}
		}

		public class DependencyResolver : IDependencyResolver {
			private readonly IKernel kernel;

			public DependencyResolver(IKernel kernel) {
				this.kernel = kernel;
			}

			public object GetService(Type serviceType) {
				return this.kernel.TryGet(serviceType, new IParameter[0]);
			}

			public IEnumerable<object> GetServices(Type serviceType) {
				return this.kernel.GetAll(serviceType, new IParameter[0]);
			}
		}

		public class UnitOfWork : IDisposable {
			private IKernel kernel;
			private ISession session;
			private ITransaction trans;

			public UnitOfWork(IKernel kernel) {
				this.kernel = kernel;
				session = this.kernel.TryGet<ISession>(new IParameter[0]);
				trans = session.BeginTransaction();
			}

			public void Dispose() {
				trans.Commit();
				session.Close();
			}

		}

		[SetUp]
		public void Setup() {
			Assert.DoesNotThrow(new TestDelegate(TestConfig));
			this.kernel = new StandardKernel(new NinjectModule[] { new mvcForum.Core.MVCForumModule(), new mvcForum.FluentnHibernate.MVCForumModule(), new TestModule() });
			ISession session = this.kernel.TryGet<ISession>(new IParameter[0]);
			using (ITransaction trans = session.BeginTransaction()) {
				FluentnHibernate.FluentInstaller installer = new FluentnHibernate.FluentInstaller();
				installer.BeforeInstall(new DependencyResolver(this.kernel));
				trans.Commit();
			}
			session.Close();
		}

		private void TestConfig() {
			string temp = ConfigurationManager.ConnectionStrings["MainDBEF"].ConnectionString;
		}

		[Test]
		public void CanCreateBoard() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);
				var board = elementRepo.CreateBoard("FirstBoard");

				var getBoard = elementRepo.ReadBoard(board.Id);

				Assert.AreEqual(board.Id, getBoard.Id);
				Assert.AreEqual(board.Name, getBoard.Name);
			}
		}

		[Test]
		public void CanCreateCategory() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);
				var board = elementRepo.CreateBoard("FirstBoard");

				var category = elementRepo.CreateCategory(board, "First category", 10);

				var getCategory = elementRepo.ReadCategory(category.Id);

				Assert.AreEqual(category.Id, getCategory.Id);
				Assert.AreEqual(category.Name, getCategory.Name);
				Assert.AreEqual(category.SortOrder, getCategory.SortOrder);
			}
		}

		[Test]
		public void CanCreateForum() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);
				var board = elementRepo.CreateBoard("FirstBoard");
				var category = elementRepo.CreateCategory(board, "FirstCategory", 10);

				var forum = elementRepo.CreateForum(category, "FirstForum", "the first forum", 10);

				var getForum = elementRepo.ReadForum(forum.Id);

				Assert.AreEqual(forum.Id, getForum.Id);
				Assert.AreEqual(forum.Name, getForum.Name);
				Assert.AreEqual(forum.SortOrder, getForum.SortOrder);
				Assert.AreEqual(forum.Description, getForum.Description);
			}
		}

		[Test]
		public void CanCreateSubForum() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);
				var board = elementRepo.CreateBoard("FirstBoard");
				var category = elementRepo.CreateCategory(board, "FirstCategory", 10);
				var forum = elementRepo.CreateForum(category, "FirstForum", "the first forum", 10);

				var subForum = elementRepo.CreateForum(category, "FirstSubForum", "the first sub forum", 10);

				var getForum = elementRepo.ReadForum(subForum.Id);

				Assert.AreEqual(subForum.Id, getForum.Id);
				Assert.AreEqual(subForum.Name, getForum.Name);
				Assert.AreEqual(subForum.SortOrder, getForum.SortOrder);
				Assert.AreEqual(subForum.Description, getForum.Description);
			}
		}

		[Test]
		public void CanCreateGroup() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);

				var group = elementRepo.CreateGroup("FirstGroup");

				var getGroup = elementRepo.ReadGroup(group.Id);

				Assert.AreEqual(group.Id, getGroup.Id);
				Assert.AreEqual(group.Name, getGroup.Name);
			}
		}

		[Test]
		public void CanCreateAccessMask() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);
				var board = elementRepo.CreateBoard("FirstBoard");
				elementRepo.UpdateBoard(board);
			}

			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var mask = elementRepo.CreateAccessMask(board, "FirstAccessMask", AccessFlag.Edit);
			}

			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var getMask = elementRepo.ReadAccessMask(mask.Id);

				Assert.AreEqual(mask.Id, getMask.Id);
				Assert.AreEqual(mask.Name, getMask.Name);
				Assert.AreEqual(mask.AccessFlag, getMask.AccessFlag);
				Assert.AreEqual(mask.BoardId, getMask.BoardId);
			}
		}

		[Test]
		public void CanCreateForumSettings() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);
				var forumSettings = elementRepo.CreateForumSettings("ForumSettings", "TheValue");

				var getForumSettings = elementRepo.ReadForumSettings("ForumSettings");

				Assert.AreEqual(forumSettings.Id, getForumSettings.Id);
				Assert.AreEqual(forumSettings.Key, forumSettings.Key);
				Assert.AreEqual(forumSettings.Value, forumSettings.Value);
				Assert.AreEqual(forumSettings.Key, "ForumSettings");
				Assert.AreEqual(forumSettings.Value, "TheValue");
			}
		}

		[Test]
		public void CanCreateForumAccess() {
			using (UnitOfWork request = new UnitOfWork(this.kernel)) {
				var elementRepo = this.kernel.TryGet<IElementRepository>(new IParameter[0]);
				var board = elementRepo.CreateBoard("FirstBoard");
				var category = elementRepo.CreateCategory(board, "FirstCategory", 10);

				var forum = elementRepo.CreateForum(category, "FirstForum", "the first forum", 10);
				var mask = elementRepo.CreateAccessMask(board, "FirstAccessMask", AccessFlag.Edit);
				var group = elementRepo.CreateGroup("FirstGroup");

				var forumAccess = elementRepo.CreateForumAccess(forum, group, mask);

				var getForumAccess = elementRepo.ReadForumAccess(forum, group);

				Assert.AreEqual(forumAccess.Id, getForumAccess.Id);
				Assert.AreEqual(forumAccess.AccessMaskId, getForumAccess.AccessMaskId);
				Assert.AreEqual(forumAccess.ForumId, getForumAccess.ForumId);
				Assert.AreEqual(forumAccess.GroupId, getForumAccess.GroupId);
			}
		}
	}
}